package hh.util.time;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;

/**
 * 程序计时工具 ，支持多任务，开始，暂停，恢复，结束
 * startTime    1
 * <p>
 * pause1       5
 * resume1      7
 * <p>
 * pause2       8
 * resume2      10
 * <p>
 * stop         11
 * time =   11-(2+2) - 1
 */
@Slf4j
public class StopWatch {
    static final int nanoToMS = 1000000;

    public boolean isStarted() {
        return timerTask.isStarted();
    }

    public boolean isStopped() {
        return timerTask.isStopped();
    }

    public boolean isPaused() {
        return timerTask.isPaused();
    }

    public boolean start() {
        return timerTask.start();
    }

    public long stop() {
        return timerTask.stop();
    }

    public long pause() {
        return timerTask.pause();
    }

    public void resume() {
        timerTask.resume();
    }

    public long getNanoTime() {
        return timerTask.getNanoTime();
    }

    public long getTime() {
        return timerTask.getTime();
    }

    TimerTask timerTask = new TimerTask(Thread.currentThread());

    Map<Thread, TimerTask> threadLocalTimerTask;


    @Data
    public static class TimerTask {
        static final int INIT = 0; //new
        static final int STARTED = 1; //开始
        static final int STOPPED = 2; //停止
        static final int PAUSED = 3; //暂停
        private String taskName;

        private String threadName; // 线程名
        private long threadId; // 线程id

        private long startTime = System.nanoTime(); // 开始时间
        private long endTime; // 结束时间
        private long relativeStartTime = startTime; // 暂停后的相对开始时间，暂停就像当于把开始时间提前了
        private long pauseTime; // 暂停时间


        private int state = INIT; // 状态

        public TimerTask(Thread currentThread) {
            if (currentThread != null) {
                this.threadId = currentThread.getId();
                this.threadName = currentThread.getName();
                if (this.taskName == null) {
                    this.taskName = this.threadName;
                }
            }
        }

        public TimerTask(String name, Thread currentThread) {
            this(currentThread);
            this.taskName = name;
        }

        public boolean isStarted() {
            return state == STARTED;
        }

        public boolean isStopped() {
            return state == STOPPED;
        }

        public boolean isPaused() {
            return state == PAUSED;
        }

        public boolean start() {
            if (state == INIT || isStopped()) {
                startTime = System.nanoTime();
                relativeStartTime = startTime;
                state = STARTED;
                pauseTime = 0;
                endTime = 0;
                return true;
            }
            return false;
        }

        public long stop() {
            endTime = System.nanoTime();
            resume();
            state = STOPPED;
            return (endTime - relativeStartTime) / nanoToMS;
        }

        public long pause() {
            if (state == STARTED) {
                state = PAUSED;
                pauseTime = System.nanoTime();
            }
            return getTime();
        }

        public void resume() {
            if (state == PAUSED) {
                state = STARTED;
                relativeStartTime = relativeStartTime + (System.nanoTime() - pauseTime);
            }
        }

        public long getNanoTime() {
            return endTime - relativeStartTime;
        }

        public long getTime() {
            long et = endTime;
            if (isPaused()) {
                et = pauseTime;
            } else if (et == 0) {
                et = System.nanoTime();
            }
            return (et - relativeStartTime) / nanoToMS;
        }
    }


}
